﻿using System;
using System.Diagnostics;

namespace Socium.Presentation {
	/// <summary>
	/// A command whose sole purpose is to 
	/// relay its functionality to other
	/// objects by invoking delegates. The
	/// default return value for the CanExecute
	/// method is 'true'.
	/// </summary>
	public class Command : CommandBase {
		#region Fields

		readonly Action _execute;
		readonly Func<bool> _can_execute;

		#endregion // Fields

		#region Constructors

		/// <summary>
		/// Creates a new command that can always execute.
		/// </summary>
		/// <param name="execute">The execution logic.</param>
		public Command(Action execute) : this(execute, null) {
		}

		/// <summary>
		/// Creates a new command.
		/// </summary>
		/// <param name="execute">The execution logic.</param>
		/// <param name="can_execute">The execution status logic.</param>
		public Command(Action execute, Func<bool> can_execute) {
			if (execute == null) {
				throw new ArgumentNullException("execute");
			}

			_execute = execute;
			_can_execute = can_execute;
		}

		#endregion // Constructors

		#region ICommand Members

		[Conditional("DEBUG")]
		[DebuggerStepThrough]
		void CheckParameter(object parameter) {
			if (parameter != null) {
				throw new ArgumentException(string.Format("Parameter {0} is not null", parameter), "parameter");
			}
		}

		[DebuggerStepThrough]
		public override bool CanExecute(object parameter) {
			CheckParameter(parameter);

			return _can_execute == null || _can_execute();
		}

		public override void Execute(object parameter) {
			CheckParameter(parameter);

			_execute();
		}

		#endregion // ICommand Members
	}

	public class Command<T> : CommandBase {
		readonly Action<T> _execute;
		readonly Predicate<T> _can_execute;

		public Command(Action<T> execute) : this(execute, null) {}

		public Command(Action<T> execute, Predicate<T> can_execute) {
			_execute = execute;
			_can_execute = can_execute;
		}

		static T CastParameter(object parameter) {
			return (T) parameter;
		}

		public override void Execute(object parameter) {
			_execute(CastParameter(parameter));
		}

		public override bool CanExecute(object parameter) {
			return _can_execute == null || _can_execute(CastParameter(parameter));
		}
	}
}